//------------------------------------
//	LED Matrix Display 5x7 (4-digit) -
//	      Version 1.0 (6/2014)		 -
//		       Mega8A/16Mhz			 -
//------------------------------------
// LED Display TBA40-11EGWA Red/Green (Common Catode)

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define F_CPU 16000000UL

#define IN_BUTTON	PC1
#define	OUT_SER		PB0
#define	OUT_SCK		PB1
#define	OUT_SCL		PB2
#define	OUT_RCK		PC0
#define OUT_ROW_1	PD1
#define OUT_ROW_2	PD2
#define OUT_ROW_3	PD3
#define OUT_ROW_4	PD4
#define OUT_ROW_5	PD5
#define OUT_ROW_6	PD6
#define OUT_ROW_7	PD7

#define CharWidth	5
#define DispWidth	20
#define	COLOR_RED	0
#define COLOR_GREEN	1

// Declaration of procedures

void IO_init();
void Col_Out();
void Row_Out();
void WriteRowToPos(uint8_t CharRowData,int16_t Position,int8_t color);
void UART_init();
int receive();


// Declaration of variables

uint8_t Colls_Out[5];
uint8_t Colls_Out_Red_temp[5];
uint8_t Colls_Out_Green_temp[5];
uint8_t DigCmd[23]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,'-','@',' '};
uint8_t DigValue[23]={0x41,0xDD,0xA1,0x89,0x1D,0x0B,0x03,0xD9,0x01,0x09,0x40,0xDC,0xA0,0x88,0x1C,0x0A,0x02,0xD8,0x00,0x08,0xBF,0x73,0xFF};
uint8_t temp=1;
uint8_t digit=1,dig_1=' ',dig_2=' ',dig_3=' ',dig_4=0;
//uint8_t digit=1,dig_1=18,dig_2=18,dig_3=18,dig_4=18;
uint8_t act_digit,table,found,res_digit,res_seg,period=0,anim=1;
uint8_t Row_Cnt;

//******* Main cycle *******

int main()
{
	int8_t temp_pos;
	temp_pos=17;
	WriteRowToPos(0x1F,temp_pos,COLOR_GREEN);	
		
	IO_init();
	sei();

	Colls_Out[0]=0xFF;
	Colls_Out[1]=0xC0;
	Colls_Out[2]=0x00;
	Colls_Out[3]=0x03;
	Colls_Out[4]=0xFF;
	
	while (1)
	{

	}
}

//***************
void IO_init()
{
	UART_init();
	DDRB=(1<<OUT_SER) | (1<<OUT_SCK) | (1<<OUT_SCL);
	PORTB=0x00;
	DDRD=(1<<OUT_ROW_1) | (1<<OUT_ROW_2) | (1<<OUT_ROW_3) | (1<<OUT_ROW_4) | (1<<OUT_ROW_5) | (1<<OUT_ROW_6) | (1<<OUT_ROW_7);
	PORTD=(1<<PD0);
	DDRC=(1<<OUT_RCK);
	PORTC=(1<<IN_BUTTON);
	OCR1A=1999;
	TCCR1B=(1<<WGM12)+(1<<CS11);
	TIMSK=(1<<OCIE1A);

//	wdt_enable(WDTO_15MS);
}
//*********** RX ***********
ISR (USART_RXC_vect)
{
	uint8_t rx_byte,address,d1,d2,d3,d4,crc;

	UCSRB&=~(1<<RXCIE);		// Disable RX Interrupt
	sei();					// Enable Global Interrupt

	address=((~(PIND)&0x06)>>1)+0x30;

	rx_byte=UDR;
	switch (rx_byte)
	{
		case 'D':					// 'DISP','<address>',<dig1>,<dig1>,<dig1>,<dig1>,<digit_crc>
			if (receive()!='I') break;
			if (receive()!='S') break;
			if (receive()!='P') break;
			if (receive()!=address) break;
			d1=receive();
			d2=receive();
			d3=receive();
			d4=receive();
			crc=receive();

			if ((d1+d2+d3+d4)!=crc) break;

			dig_1=d1;
			dig_2=d2;
			dig_3=d3;
			dig_4=d4;

			break;

		default:
			break;
	}

	UCSRB|=(1<<RXCIE);		// Enable RX Interrupt
 
}

//************ TIMER ***************
ISR (TIMER1_COMPA_vect)
{
	
	//Colls_Out[0]=0x00;
	//Colls_Out[1]=0x00;
	//Colls_Out[2]=0x00;
	//Colls_Out[3]=0x00;
	//Colls_Out[4]=0x00;

	//WriteRowToPos(0x1F,-2,COLOR_RED);
	
	Col_Out();
	Row_Out();


	wdt_reset();
}

//******** Write to External Out ********
void Col_Out()
{
	uint8_t ext_out_temp;
	uint8_t	ext_bits_cnt;
	uint8_t ext_digits_cnt;
	uint8_t temp_PORTD;

	PORTC&=~(1<<OUT_RCK);	// RCLK

	PORTB&=~(1<<OUT_SCL);	// SCL
	PORTB|=(1<<OUT_SCL);

	for (ext_digits_cnt=0;ext_digits_cnt<5;ext_digits_cnt++)
	{
		ext_out_temp=Colls_Out[ext_digits_cnt];
		for (ext_bits_cnt=0;ext_bits_cnt<8;ext_bits_cnt++)
		{
			if (ext_out_temp&0x80) PORTB|=(1<<OUT_SER);
			else PORTB&=~(1<<OUT_SER);
			ext_out_temp=ext_out_temp<<1;
			PORTB|=(1<<OUT_SCK);	// CLK
			//_delay_us(1);
			PORTB&=~(1<<OUT_SCK);	// CLK
		}
	}

	// Switch OFF all Rows
	PORTD&=~0xFE;
	
	// Turn ON transfered Columns
	PORTC|=(1<<OUT_RCK);	// RCLK

	//Switch ON requested Row
	temp_PORTD=PORTD&0x01;
	temp_PORTD|=(1<<Row_Cnt);
	PORTD=temp_PORTD;
}

void Row_Out()
{
	uint8_t temp_PORTD;
	
	switch (Row_Cnt)
	{
		case 1:
		Colls_Out[0]=0xFF;
		Colls_Out[1]=0x80;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x03;
		Colls_Out[4]=0xFF;
		break;
		
		case 2:
		Colls_Out[0]=0xF0;
		Colls_Out[1]=0x40;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x03;
		Colls_Out[4]=0xF2;
		break;

		case 3:
		Colls_Out[0]=0x48;
		Colls_Out[1]=0xC0;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x03;
		Colls_Out[4]=0xF8;
		break;

		case 4:
		Colls_Out[0]=0x11;
		Colls_Out[1]=0x00;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x01;
		Colls_Out[4]=0x48;
		break;

		case 5:
		Colls_Out[0]=0x33;
		Colls_Out[1]=0xC0;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x02;
		Colls_Out[4]=0x82;
		break;

		case 6:
		Colls_Out[0]=0x44;
		Colls_Out[1]=0xC0;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x00;
		Colls_Out[4]=0x44;
		break;

		case 7:
		Colls_Out[0]=0x88;
		Colls_Out[1]=0xC0;
		Colls_Out[2]=0x00;
		Colls_Out[3]=0x01;
		Colls_Out[4]=0x01;
		break;
		
		default:
		break;
	}
	
	Row_Cnt++;
	if (Row_Cnt>7) Row_Cnt=1;

}

void WriteRowToPos(uint8_t CharRowData,int16_t Position,int8_t color)
{	
	int8_t startByte;
	int8_t startBit;
	int8_t stopByte;
	int8_t stopBit;
	uint8_t charRowData_Temp;
	uint8_t charRowData_mask_1;
	uint8_t charRowData_mask_2;
	

	if (((Position+CharWidth)<=0)||(Position>(DispWidth-1))) return;

	startByte=Position/8;
	startBit=Position%8;
	stopByte=(Position+CharWidth-1)/8;
	stopBit=(Position+CharWidth-1)%8;
	
	charRowData_mask_1=(1<<CharWidth)-1;
	charRowData_mask_2=(1<<CharWidth)-1;
	if ((Position+CharWidth)>DispWidth)
	{
		charRowData_mask_1=charRowData_mask_1<<((Position+CharWidth)-DispWidth);
		charRowData_mask_2=0x00;
	}
	if (Position<0)
	{
		charRowData_mask_1=0x00;
		charRowData_mask_2=charRowData_mask_2<<((Position+CharWidth)-DispWidth);
	}
		
	if (Position>=0)
	{
		charRowData_Temp=(CharRowData&charRowData_mask_1)<<((8-CharWidth));
		charRowData_Temp=charRowData_Temp>>startBit;
		if (color==COLOR_RED) Colls_Out_Red_temp[startByte]|=charRowData_Temp;
		if (color==COLOR_GREEN) Colls_Out_Green_temp[startByte]|=charRowData_Temp; 
	}
	
	if ((((Position+CharWidth)<DispWidth) && (startByte!=stopByte)) || (Position<0))
	{
		charRowData_Temp=(CharRowData&charRowData_mask_2)<<((8-CharWidth));
		charRowData_Temp=charRowData_Temp<<(CharWidth-stopBit-1);
		if (color==COLOR_RED) Colls_Out_Red_temp[stopByte]|=charRowData_Temp;
		if (color==COLOR_GREEN) Colls_Out_Green_temp[stopByte]|=charRowData_Temp;
	}
}